home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / ghostscript / 8.64 / Resource / Init / gs_setpd.ps < prev    next >
Encoding:
Text File  |  2009-04-17  |  29.3 KB  |  925 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: gs_setpd.ps 9350 2009-01-13 18:38:37Z ray $
  14. % The current implementation of setpagedevice has the following limitations:
  15. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  16.  
  17. languagelevel 1 .setlanguagelevel
  18. level2dict begin
  19.  
  20. % ---------------- Redefinitions ---------------- %
  21.  
  22. % Redefine .beginpage and .endpage so that they call BeginPage and
  23. % EndPage respectively if appropriate.
  24.  
  25. % We have to guard against the BeginPage procedure not popping its operand.
  26. % This is really stupid, but the Genoa CET does it.
  27. /.beginpage {        % - .beginpage -
  28.   .currentshowpagecount {
  29.     .currentpagedevice pop
  30.     dup //null ne { /BeginPage .knownget } { pop //false } ifelse {
  31.         % Stack: ... pagecount proc
  32.        count 2 .execn
  33.         % Stack: ... ..???.. oldcount
  34.        count 1 add exch sub { pop } repeat
  35.     } {
  36.       pop
  37.     } ifelse
  38.   } if
  39. } bind odef
  40.  
  41. % Guard similarly against EndPage not popping its operand.
  42. /.endpage {        % <reason> .endpage <print_bool>
  43.   .currentshowpagecount {
  44.     1 index .currentpagedevice pop
  45.     dup //null ne { /EndPage .knownget } { pop //false } ifelse {
  46.         % Stack: ... reason pagecount reason proc
  47.       count 2 .execn
  48.         % Stack: ... ..???.. print oldcount
  49.       count 2 add exch sub { exch pop } repeat
  50.     } {
  51.       pop pop 2 ne
  52.     } ifelse
  53.   } {
  54.     2 ne
  55.   } ifelse
  56. } bind odef
  57.  
  58. % Define interpreter callouts for handling gstate-saving operators,
  59. % to make sure that they create a page device dictionary for use by
  60. % the corresponding gstate-restoring operator.
  61. % We'd really like to avoid the cost of doing this, but we don't see how.
  62. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  63. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  64. % interpreter.
  65.  
  66. (%gsavepagedevice) cvn
  67.  { currentpagedevice pop gsave
  68.  } bind def
  69.  
  70. (%savepagedevice) cvn
  71.  { currentpagedevice pop save
  72.  } bind def
  73.  
  74. (%gstatepagedevice) cvn
  75.  { currentpagedevice pop gstate
  76.  } bind def
  77.  
  78. (%copygstatepagedevice) cvn
  79.  { currentpagedevice pop copy
  80.  } bind def
  81.  
  82. (%currentgstatepagedevice) cvn
  83.  { currentpagedevice pop currentgstate
  84.  } bind def
  85.  
  86. % Define interpreter callouts for handling gstate-restoring operators
  87. % when the current page device needs to be changed.
  88. % The names %grestorepagedevice, %grestoreallpagedevice,
  89. % %restorepagedevice, %restore1pagedevice, and %setgstatepagedevice
  90. % are known to the interpreter.
  91.  
  92. /.installpagedevice
  93.  {    % Since setpagedevice doesn't create new device objects,
  94.     % we must (carefully) reinstall the old parameters in
  95.     % the same device.
  96.    .currentpagedevice pop //null currentdevice //null .trysetparams
  97.    dup type /booleantype eq
  98.     { pop pop }
  99.     {        % This should never happen!
  100.       SETPDDEBUG { (Error in .trysetparams!) = pstack flush } if
  101.       cleartomark pop pop pop
  102.       /.installpagedevice cvx /rangecheck signalerror
  103.     }
  104.    ifelse pop pop
  105.     % A careful reading of the Red Book reveals that an erasepage
  106.     % should occur, but *not* an initgraphics.
  107.    erasepage .beginpage
  108.  } bind def
  109.  
  110. /.uninstallpagedevice
  111.  { 2 .endpage { .currentnumcopies //false .outputpage } if
  112.    nulldevice
  113.  } bind def
  114.  
  115. (%grestorepagedevice) cvn
  116.  { .uninstallpagedevice grestore .installpagedevice
  117.  } bind def
  118.  
  119. (%grestoreallpagedevice) cvn
  120.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  121.  } bind def
  122.  
  123. (%restore1pagedevice) cvn
  124.  { .uninstallpagedevice grestore .installpagedevice restore
  125.  } bind def
  126.  
  127. (%restorepagedevice) cvn
  128.  { .uninstallpagedevice restore .installpagedevice
  129.  } bind def
  130.  
  131. (%setgstatepagedevice) cvn
  132.  { .uninstallpagedevice setgstate .installpagedevice
  133.  } bind def
  134.  
  135. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  136. /.numcopiesdict mark
  137.   /NumCopies dup
  138. .dicttomark readonly def
  139.  
  140. /.currentnumcopies
  141.  { currentdevice //.numcopiesdict .getdeviceparams
  142.    dup type /integertype eq
  143.     { exch pop exch pop }
  144.     { cleartomark #copies }
  145.    ifelse
  146.  } bind odef
  147.  
  148. % Redefine .currentpagedevice and .setpagedevice so they convert between
  149. % null and a fixed empty directionary.
  150. /.nullpagedevice 0 dict readonly def
  151. /.currentpagedevice {
  152.   //.currentpagedevice exch dup //null eq { pop //.nullpagedevice } if exch
  153. } bind odef
  154. /.setpagedevice {
  155.   dup //.nullpagedevice eq { pop //null } if //.setpagedevice
  156. } bind odef
  157.  
  158. % ---------------- Auxiliary definitions ---------------- %
  159.  
  160. % Define the required attributes of all page devices, and their default values.
  161. % We don't include attributes such as .MediaSize, which all devices
  162. % are guaranteed to supply on their own.
  163. /.defaultpolicies mark
  164.   % M. Sweet, Easy Software Products
  165.   %
  166.   % Due to the fact that it is not possible to properly implement
  167.   % the selection policies from a Ghostscript driver, we have changed
  168.   % the default policy to "7" (impose) to avoid numerous problems with
  169.   % printing within CUPS...
  170.   %
  171.   NOMEDIAATTRS {
  172.     /PolicyNotFound 7
  173.     /PageSize 7
  174.   } {
  175.     /PolicyNotFound 1
  176.     /PageSize 0
  177.   } ifelse
  178.   /PolicyReport {
  179.     dup /.LockSafetyParams known {
  180.     % Only possible error is invalidaccess
  181.       /setpagedevice .systemvar /invalidaccess signalerror
  182.     }
  183.     if
  184.     pop
  185.   } bind
  186. .dicttomark readonly def
  187. % Note that the values of .requiredattrs are executed, not just fetched.
  188. /.requiredattrs mark
  189.   /PageDeviceName //null
  190.   /PageOffset [0 0] readonly
  191. % We populate InputAttributes with all of the known page sizes 
  192. % followed by a dummy media type that handles pages of any size.
  193. % This will create some duplicates, but that only slightly slows
  194. % down the media selection (loop is in zmedia2.c).
  195. %
  196. % Some PostScript creators assume that slot 0 is the default media
  197. % size and some can't handle a non-standard 4-element array which
  198. % is a 'range' type page size (always put last).
  199. %
  200. % Real Devices that can only handle specific page sizes will override this.
  201.   /InputAttributes {
  202.     mark
  203.     % First put the device's default page size in slot 0
  204.     % This satifies those that have devices built with a4 as the default
  205.     0 mark /PageSize currentdevice /PageSize gsgetdeviceprop .dicttomark
  206.     statusdict /.pagetypenames get {
  207.       counttomark 1 sub 2 idiv exch mark exch /PageSize exch
  208.       % stack: mark --dict-- --dict-- ... key mark /PageSize pagetypename
  209.       % see note above about pagetype executable array contents.
  210.       load dup 0 get exch 1 get 2 array astore .dicttomark
  211.     } forall
  212.     % If NORANGEPAGESIZE is defined, (-dNORANGEPAGESIZE), then don't add
  213.     % the 'match any' PageSize entry
  214.     systemdict /NORANGEPAGESIZE known not {
  215.       % Add one last entry which is the 4 element range array (non-standard)
  216.       counttomark 2 idiv 
  217.     % PageSize with either dimension 0 will be detected in
  218.     % match_page_size, so we can allow it here
  219.       mark /PageSize [0 dup 16#7ffff dup] .dicttomark
  220.     } if
  221.     .dicttomark
  222.   }
  223.   (%MediaSource) 0
  224.   /OutputAttributes {
  225.     mark 0 mark .dicttomark readonly .dicttomark
  226.   }
  227.   (%MediaDestination) 0
  228.   /Install {{.callinstall}} bind
  229.   /BeginPage {{.callbeginpage}} bind
  230.   /EndPage {{.callendpage}} bind
  231.   /Policies .defaultpolicies
  232.   /ImagingBBox //null        % default value
  233.   /UseCIEColor /.getuseciecolor load
  234. .dicttomark readonly def
  235.  
  236. % Define currentpagedevice so it creates the dictionary on demand if needed,
  237. % adding all the required entries defined just above.
  238. % We have to deal specially with entries that the driver may change
  239. % on its own.
  240. /.dynamicppkeys mark
  241.   /.MediaSize dup        % because it changes when PageSize is set
  242. %  /LeadingEdge dup
  243.   /PageCount dup
  244.   /Colors dup
  245.   /BitsPerPixel dup
  246.   /ColorValues dup
  247. .dicttomark readonly def
  248. /.makecurrentpagedevice {    % - .makecurrentpagedevice <dict>
  249.   currentdevice //null .getdeviceparams
  250.     % Make the dictionary large enough to add defaulted entries.
  251.   counttomark 2 idiv .requiredattrs length add dict
  252.   counttomark 2 idiv { dup 4 2 roll put } repeat exch pop
  253.     % Add any missing required attributes.
  254.     % Make a writable and (if possible) local copy of any default
  255.     % dictionaries, to work around a bug in the output of WordPerfect,
  256.     % which assumes that these dictionaries are writable and local.
  257.   .currentglobal exch dup gcheck .setglobal
  258.   .requiredattrs {
  259.     2 index 2 index known {
  260.       1 index /Policies eq {
  261.     % Merge policies from the device driver with defaults
  262.     2 index             % <<>> /key value <<>>
  263.     3 2 roll get        % <<>> value <<policies>>
  264.     exch {                
  265.       2 index 2 index known { 
  266.         pop pop
  267.       } { 
  268.         2 index 3 1 roll put
  269.       } ifelse
  270.     } forall
  271.     pop
  272.       } {
  273.     pop pop
  274.       } ifelse
  275.     } {
  276.       exec 2 index 3 1 roll put
  277.     } ifelse
  278.   } forall exch .setglobal
  279.   dup .setpagedevice
  280. } bind def
  281. /currentpagedevice {
  282.   .currentpagedevice {
  283.     dup length 0 eq {
  284.       pop .makecurrentpagedevice
  285.     } {
  286.         % If any of the dynamic keys have changed,
  287.         % we must update the page device dictionary.
  288.       currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {
  289.         % Stack: current key value
  290.         2 index 2 index .knownget { 1 index ne } { //true } ifelse
  291.          { 2 index wcheck not
  292.         {    % This is the first entry being updated.
  293.             % Copy the dictionary to make it writable.
  294.           3 -1 roll
  295.           currentglobal 1 index dup gcheck currentglobal and setglobal
  296.           length dict
  297.           exch setglobal
  298.           .copydict
  299.           3 1 roll
  300.         }
  301.            if
  302.            2 index 3 1 roll put
  303.          }
  304.          { pop pop
  305.          }
  306.         ifelse
  307.       } forall
  308.       % If the device is the distiller device, update distillerparams that
  309.       % may have been changed by setdistillerparams
  310.       currentdevice .devicename /pdfwrite eq {
  311.     currentdistillerparams {
  312.           % Stack: current key value
  313.       2 index 2 index .knownget { 1 index ne } { //true } ifelse
  314.       { 2 index 3 1 roll put } { pop pop } ifelse
  315.     } forall
  316.       } if
  317.         % If the dictionary was global and is now local, copy
  318.         % any global subsidiary dictionaries to local VM.  This
  319.         % too is to work around the Word Perfect bug (see above).
  320.       dup gcheck not {
  321.     dup {
  322.       dup type /dicttype eq { dup gcheck } { //false } ifelse {
  323.         % Copy-on-write, see above.
  324.         2 index wcheck not {
  325.           3 -1 roll dup length dict .copydict
  326.           3 1 roll
  327.         } if
  328.         .copytree 2 index 3 1 roll put
  329.       } {
  330.         pop pop
  331.       } ifelse
  332.     } forall
  333.       } if
  334.         % We would like to do a .setpagedevice so we don't keep
  335.         % re-creating the dictionary.  Unfortunately, the effect
  336.         % of this is that if any dynamic key changes (PageCount
  337.         % in particular), we will do the equivalent of a
  338.         % setpagedevice at the next restore or grestore.
  339.         % Therefore, we make the dictionary read-only, but
  340.         % we don't store it away.  I.e., NOT:
  341.         % dup wcheck { .setpagedevice .currentpagedevice pop } if
  342.       readonly
  343.     } ifelse
  344.   } if
  345. } bind odef
  346.  
  347. % Copy a dictionary recursively.
  348. /.copytree {    % <dict> .copytree <dict'>
  349.   dup length dict exch {
  350.     dup type /dicttype eq { .copytree } if 2 index 3 1 roll put
  351.   } forall
  352. } bind def
  353.  
  354. % The implementation of setpagedevice is quite complex.  Currently,
  355. % everything but the media matching algorithm is implemented here.
  356.  
  357. % By default, we only present the requested changes to the device,
  358. % but there are some parameters that require special merging action.
  359. % Define those parameters here, with the procedures that do the merging.
  360. % The procedures are called as follows:
  361. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  362. /.mergespecial mark
  363.   /InputAttributes
  364.    { dup //null eq
  365.       { pop //null
  366.       }
  367.       { 3 copy pop .knownget
  368.      { dup //null eq
  369.         { pop dup length dict }
  370.         { dup length 2 index length add dict .copydict }
  371.        ifelse
  372.      }
  373.      { dup length dict
  374.      }
  375.         ifelse .copydict readonly
  376.       }
  377.      ifelse
  378.    } bind
  379.   /OutputAttributes 1 index
  380.   /Policies
  381.     { 3 copy pop .knownget
  382.        { dup length 2 index length add dict .copydict }
  383.        { dup length dict }
  384.       ifelse copy readonly
  385.     } bind
  386. .dicttomark readonly def
  387.  
  388. % M. Sweet, Easy Software Products:
  389. %
  390. % Define NOMEDIAATTRS to turn off the default (but unimplementable) media
  391. % selection policies for setpagedevice.  This is used by CUPS to support
  392. % the standard Adobe media attributes.
  393. NOMEDIAATTRS {
  394.   % Define only PageSize for input attribute matching.
  395.   /.inputattrkeys [
  396.     /PageSize
  397.   ] readonly def
  398.   % Define no other keys used in media selection.
  399.   /.inputselectionkeys [
  400.     /noInputSelectionsKeys
  401.   ] readonly def
  402.  
  403.   % Define no keys used in output attribute matching.
  404.   /.outputattrkeys [
  405.     /noOutputAttrKeys
  406.   ] readonly def
  407. } {
  408.   % Define the keys used in input attribute matching.
  409.   /.inputattrkeys [
  410.     /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet /ManualFeed
  411.       % The following are documented in Adobe's supplement for v2017.
  412.     /LeadingEdge /MediaClass
  413.   ] readonly def
  414.   % Define other keys used in media selection.
  415.   /.inputselectionkeys [
  416.     /MediaPosition /Orientation
  417.   ] readonly def
  418.  
  419.   % Define the keys used in output attribute matching.
  420.   /.outputattrkeys [
  421.     /OutputType
  422.   ] readonly def
  423. } ifelse
  424.  
  425. % Define all the parameters that should always be copied to the merged
  426. % dictionary.
  427. /.copiedkeys [
  428.   /OutputDevice
  429.   .mergespecial { pop } forall
  430.   .inputattrkeys aload pop
  431.   .inputselectionkeys aload pop
  432.   .outputattrkeys aload pop
  433. ] readonly def
  434.  
  435. % Define the parameters that should not be presented to the device.
  436. % The procedures are called as follows:
  437. %    <merged> <key> <value> -proc-
  438. % The procedure leaves all its operands on the stack and returns
  439. % true iff the key/value pair should be presented to .putdeviceparams.
  440. /.presentspecial mark
  441.   .dynamicppkeys
  442.       { pop dup /LeadingEdge ne { //false } { pop } ifelse }
  443.   forall
  444.             % We must ignore an explicit request for .MediaSize,
  445.             % because media matching always handles this.
  446.   /.MediaSize //false
  447.   /Name //false
  448.   /OutputDevice //false
  449.   /PageDeviceName //false
  450.   /PageOffset //false
  451.   /PageSize //false        % obsolete alias for .MediaSize
  452.   /InputAttributes //false
  453.   .inputattrkeys
  454.        { dup dup /PageSize eq exch /LeadingEdge eq or
  455.        { pop }
  456.        { { 2 index /InputAttributes .knownget { //null eq } { //true } ifelse } }
  457.       ifelse
  458.     }
  459.   forall
  460.   .inputselectionkeys { //false } forall
  461.   /OutputAttributes //false
  462.   .outputattrkeys
  463.     { { 2 index /OutputAttributes .knownget { //null eq } { //true } ifelse } }
  464.   forall
  465.   /Install //false
  466.   /BeginPage //false
  467.   /EndPage //false
  468.   /Policies //false
  469.     % Our extensions:
  470.   /HWColorMap
  471.     {            % HACK: don't transmit the color map, because
  472.             % window systems can change the color map on their own
  473.             % incrementally.  Someday we'll have a better
  474.             % solution for this....
  475.       //false
  476.     }
  477.   /ViewerPreProcess //false
  478.   /ImagingBBox //false    % This prevents the ImagingBBox value in the setpagedevice
  479.             % from affecting the device's ImagingBBox parameter, but
  480.             % does retain a 'shadow' copy at the PostScript level.
  481.             % This is done for Adobe compatibility since Adobe does
  482.             % render marks outside the ImagingBBox (and QuarkXpress
  483.             % relies on it).
  484. .dicttomark readonly def
  485.  
  486. % Define access to device defaults.
  487. /.defaultdeviceparams
  488.  { finddevice //null .getdeviceparams
  489.  } bind def
  490.  
  491. % Select media (input or output).  The hard work is done in an operator:
  492. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  493. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  494. %    <pagedict> null <policydict> <keys> .matchmedia null true
  495. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  496.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  497.             %   .selectmedia
  498.  { 5 index 5 -2 roll 4 index .matchmedia
  499.         % Stack: orig request merged failed attrkeys mediakey
  500.         %   (key true | false)
  501.     { 4 index 3 1 roll put pop
  502.     }
  503.     {    % Adobe's implementations have a "big hairy heuristic"
  504.     % to choose the set of keys to report as having failed the match.
  505.     % For the moment, we report any keys that are in the request
  506.     % and don't have the same value as in the original dictionary.
  507.       5 index 1 index .knownget
  508.        { 4 index 3 1 roll put }
  509.        { 3 index exch .undef }
  510.       ifelse
  511.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  512.      3 index 1 index .knownget
  513.       { 5 index 2 index .knownget { ne } { pop //true } ifelse }
  514.       { //true }
  515.      ifelse        % Stack: ... <failed> <attrkey> <report>
  516.       { 2 copy /rangecheck put }
  517.      if pop
  518.        }
  519.       forall
  520.     }
  521.    ifelse
  522.  } bind def
  523.  
  524. % Apply Policies to any unprocessed failed requests.
  525. % As we process each request entry, we replace the error name
  526. % in the <failed> dictionary with the policy value,
  527. % and we replace the key in the <merged> dictionary with its prior value
  528. % (or remove it if it had no prior value).
  529. /.policyprocs mark
  530. % These procedures are called with the following on the stack:
  531. %   <orig> <merged> <failed> <Policies> <key> <policy>
  532. % They are expected to consume the top 2 operands.
  533. % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
  534. % the same as 0, i.e., we signal an error.
  535. %
  536. % M. Sweet, Easy Software Products:
  537. %
  538. % Define NOMEDIAATTRS to turn off the default (but unimplementable) media
  539. % selection policies for setpagedevice.  This is used by CUPS to support
  540. % the standard Adobe media attributes.
  541.   0 {        % Set errorinfo and signal a configurationerror.
  542.       NOMEDIAATTRS {
  543.         % NOMEDIAATTRS means that the default policy is 7...
  544.         pop 2 index exch 7 put
  545.       } {
  546.     pop dup 4 index exch get 2 array astore
  547.     $error /errorinfo 3 -1 roll put
  548.     cleartomark
  549.     /setpagedevice .systemvar /configurationerror signalerror
  550.       } ifelse
  551.   } bind
  552.   1 {        % Roll back the failed request to its previous status.
  553. SETPDDEBUG { (Rolling back.) = pstack flush } if
  554.     3 index 2 index 3 -1 roll .forceput
  555.     4 index 1 index .knownget
  556.      { 4 index 3 1 roll .forceput }
  557.      { 3 index exch .undef }
  558.     ifelse
  559.   } .bind
  560.   7 {        % For PageSize only, just impose the request.
  561.     1 index /PageSize eq
  562.      { pop pop 1 index /PageSize 7 put }
  563.      { .policyprocs 0 get exec }
  564.     ifelse
  565.   } bind
  566. .dicttomark readonly def
  567. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  568.             %   <orig> <merged'> <failed'>
  569.  { 1 index /Policies get 1 index
  570.     { type /integertype eq
  571.        { pop        % already processed
  572.        }
  573.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  574.             % Stack: <orig> <merged> <failed> <Policies> <key>
  575.             %   <policy>
  576.      .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
  577.        }
  578.       ifelse
  579.     }
  580.    forall pop
  581.  } bind def
  582.  
  583. % Prepare to present parameters to the device, by spreading them onto the
  584. % operand stack and removing any that shouldn't be presented.
  585. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  586.  { mark exch dup
  587.     {            % Stack: -mark- key1 value1 ... merged key value
  588.       .presentspecial 2 index .knownget
  589.        { exec { 3 -1 roll } { pop pop } ifelse }
  590.        { 3 -1 roll }
  591.       ifelse
  592.     }
  593.    forall pop
  594.  } bind def
  595.  
  596. % Put device parameters without resetting currentpagedevice.
  597. % (.putdeviceparams clears the current page device.)
  598. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  599.             %   <key1> <value1> ... .putdeviceparamsonly
  600.             % On success: <device> <eraseflag>
  601.             % On failure: <device> <Policies|null> <req_all> -mark-
  602.             %   <key1> <error1> ...
  603.  { .currentpagedevice
  604.     { counttomark 4 add 1 roll .putdeviceparams
  605.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  606.       .setpagedevice
  607.     }
  608.     { pop .putdeviceparams
  609.     }
  610.    ifelse
  611.  } bind def
  612.  
  613. % Try setting the device parameters from the merged request.
  614. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  615.             %   .trysetparams
  616.  { //true 4 index .prepareparams
  617.             % Add the computed .MediaSize.
  618.             % Stack: merged (ignored) device Policies -true-
  619.             %   -mark- key1 value1 ...
  620.    counttomark 5 add index .computemediasize
  621.    exch pop exch pop /.MediaSize exch
  622. SETPDDEBUG { (Putting.) = pstack flush } if
  623.    .putdeviceparamsonly
  624. SETPDDEBUG { (Result of putting.) = pstack flush } if
  625.  } bind def
  626.  
  627. % Compute the media size and initial matrix from a merged request (after
  628. % media selection).
  629. /.computemediasize    % <request> .computemediasize
  630.             %   <request> <matrix> <[width height]>
  631.  { dup /PageSize get                    % requested page size
  632.    1 index /InputAttributes get
  633.      2 index (%MediaSource) get get /PageSize get    % media size
  634.                             % (may be a range)
  635.    2 index /Policies get
  636.      dup /PageSize .knownget
  637.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  638.                             % affects scaling
  639.    3 index /Orientation .knownget not { //null } if
  640.    4 index /RollFedMedia .knownget not { //false } if
  641.    matrix .matchpagesize not {
  642.         % This is a "can't happen" condition!
  643.      /setpagedevice .systemvar /rangecheck signalerror
  644.    } if
  645.    2 array astore
  646.  } bind def
  647.  
  648. % ---------------- setpagedevice itself ---------------- %
  649.  
  650. /setpagedevice
  651.  {        % We mustn't pop the argument until the very end,
  652.         % so that the pseudo-operator machinery can restore the stack
  653.         % if an error occurs.
  654.    mark 1 index currentpagedevice
  655.  
  656.         % Check whether we are changing OutputDevice;
  657.         % also handle the case where the current device
  658.         % is not a page device.
  659.         % Stack: mark <request> <current>
  660. SETPDDEBUG { (Checking.) = pstack flush } if
  661.  
  662.    dup /OutputDevice .knownget
  663.     {        % Current device is a page device.
  664.       2 index /OutputDevice .knownget
  665.        {    % A specific OutputDevice was requested.
  666.      2 copy eq
  667.       { pop pop //null }
  668.       { exch pop }
  669.      ifelse
  670.        }
  671.        { pop //null
  672.        }
  673.       ifelse
  674.     }
  675.     {        % Current device is not a page device.
  676.         % Use the default device.
  677.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  678.     }
  679.    ifelse
  680.    dup //null eq
  681.     { pop
  682.     }
  683.     { exch pop .defaultdeviceparams
  684.         % In case of duplicate keys, .dicttomark takes the entry
  685.         % lower on the stack, so we can just append the defaults here.
  686.       .requiredattrs { exec } forall .dicttomark
  687.     }
  688.    ifelse
  689.  
  690.         % Check whether a viewer wants to intervene.
  691.         % We must check both the request (which takes precedence)
  692.         % and the current dictionary.
  693.         % Stack: mark <request> <orig>
  694.    exch dup /ViewerPreProcess .knownget
  695.     { exec }
  696.     { 1 index /ViewerPreProcess .knownget { exec } if }
  697.    ifelse exch
  698.  
  699.         % Construct a merged request from the actual request plus
  700.         % any keys that should always be propagated.
  701.         % Stack: mark <request> <orig>
  702. SETPDDEBUG { (Merging.) = pstack flush } if
  703.  
  704.    exch 1 index length 1 index length add dict
  705.    .copiedkeys
  706.     {        % Stack: <orig> <request> <merged> <key>
  707.       3 index 1 index .knownget { 3 copy put pop } if pop
  708.     }
  709.    forall
  710.         % Stack: <orig> <request> <merged>
  711.    dup 2 index
  712.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  713.       .mergespecial 2 index .knownget { exec } if
  714.       put dup
  715.     }
  716.    forall pop
  717.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  718.         % change HWResolution.
  719.    FIXEDRESOLUTION { dup /HWResolution .undef } if
  720.         % Hack: if FIXEDMEDIA is true, discard any attempt to change
  721.         % PageSize or HWSize.
  722.    FIXEDMEDIA
  723.     { dup /PageSize 4 index /PageSize get put
  724.       dup /HWSize 4 index /HWSize get put
  725.     } if
  726.         % Hack: to work around some files that take a PageSize
  727.         % from InputAttributes and impose it, discard any attempt
  728.         % to set PageSize to a 4-element value.
  729.         % Stack: mark <orig> <request> <merged>
  730.     dup /PageSize .knownget {
  731.       length 2 ne {
  732.     dup /PageSize 4 index /PageSize get put
  733.       } if
  734.     } if
  735.  
  736.         % Select input and output media.
  737.         % Stack: mark <orig> <request> <merged>
  738. SETPDDEBUG { (Selecting.) = pstack flush } if
  739.  
  740.    0 dict    % <failed>
  741.    1 index /InputAttributes .knownget
  742.     { 2 index /Policies get
  743.       .inputattrkeys (%MediaSource) cvn .selectmedia
  744.     } if
  745.    1 index /OutputAttributes .knownget
  746.     { 2 index /Policies get
  747.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  748.      } if
  749.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  750.    .applypolicies
  751.    3 -1 roll 4 1 roll        % swap back
  752.  
  753.         % Construct the new device, and attempt to set its attributes.
  754.         % Stack: mark <orig> <request> <merged> <failed>
  755. SETPDDEBUG { (Constructing.) = pstack flush } if
  756.  
  757.    currentdevice .devicename 2 index /OutputDevice get eq
  758.     { currentdevice }
  759.     { 1 index /OutputDevice get finddevice }
  760.    ifelse
  761.         %**************** We should copy the device here,
  762.         %**************** but since we can't close the old device,
  763.         %**************** we don't.  This is WRONG.
  764.     %****************copydevice
  765.    2 index /Policies get
  766.    .trysetparams
  767.    dup type /booleantype ne
  768.     {        % The request failed.
  769.         % Stack: ... <orig> <request> <merged> <failed> <device>
  770.         %   <Policies> true mark <name> <errorname> ...
  771. SETPDDEBUG { (Recovering.) = pstack flush } if
  772.       counttomark 4 add index
  773.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  774.       pop pop pop
  775.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  776.         %   <Policies>
  777.       6 2 roll 3 -1 roll 4 1 roll
  778.       .applypolicies
  779.       3 -1 roll 4 1 roll 6 -2 roll
  780.       .trysetparams        % shouldn't fail!
  781.       dup type /booleantype ne
  782.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  783.          /setpagedevice .systemvar exch signalerror
  784.        }
  785.       if
  786.     }
  787.    if
  788.  
  789.         % The attempt succeeded.  Install the new device.
  790.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  791. SETPDDEBUG { (Installing.) = pstack flush } if
  792.  
  793.    pop 2 .endpage
  794.     { 1 //true .outputpage
  795.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  796.     }
  797.    if
  798.         % .setdevice clears the current page device!
  799.    .currentpagedevice pop exch
  800.    .setdevice pop
  801.    .setpagedevice
  802.  
  803.         % Implement UseCIEColor directly if this is a LL3 system.
  804.         % The color substitution feature is now implemented in
  805.         % the interpreter, and this is used as an optimization.
  806.         %
  807.         % NB: This shoud be the only use of the .setuseciecolor
  808.         %     operator anywhere.
  809.         %
  810.         % If UseCIEColor is transitioned to false, set some
  811.         % color space other than /DeviceGray, to insure that
  812.         % initgraphics will actually perform a setcolorspace
  813.         % operation (there is an optimization in setcolorspace
  814.         % that does nothing if the operand and current color
  815.         % spaces are the same, and UseCIEColor is false).
  816.  
  817.     /.setuseciecolor where
  818.       {
  819.         pop 1 index /UseCIEColor .knownget
  820.           {
  821.             dup .setuseciecolor not
  822.               { /DeviceRGB setcolorspace }
  823.             if
  824.           }
  825.         if
  826.       }
  827.     if
  828.  
  829.         % Merge the request into the current page device,
  830.         % unless we're changing the OutputDevice.
  831.         % Stack: mark ... <merged> <failed>
  832.    exch currentpagedevice dup length 2 index length add dict
  833.         % Stack: mark ... <failed> <merged> <current> <newdict>
  834.    2 index /OutputDevice .knownget {
  835.      2 index /OutputDevice .knownget not { //null } if eq
  836.    } {
  837.      //true
  838.    } ifelse {
  839.         % Same OutputDevice, merge the dictionaries.
  840.      .copydict
  841.    } {
  842.         % Different OutputDevice, discard the old dictionary.
  843.      exch pop
  844.    } ifelse .copydict
  845.         % Initialize the default matrix, taking media matching
  846.         % into account.
  847.    .computemediasize pop initmatrix concat
  848.    dup /PageOffset .knownget
  849.     {        % Translate by the given number of 1/72" units in device X/Y.
  850.       dup 0 get exch 1 get
  851.       2 index /HWResolution get dup 1 get exch 0 get
  852.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  853.       idtransform translate
  854.     }
  855.    if
  856.         % We must install the new page device dictionary
  857.         % before calling the Install procedure.
  858.   dup .setpagedevice
  859.   .setdefaulthalftone    % Set the default screen before calling Install.
  860.   dup /Install .knownget {
  861.     { .execinstall } stopped {
  862.       pop % Install procedure failed. One element will have been left on the stack.
  863.       % stack: mark <orig> <request> <failed> <merged>
  864.       1 index /Install $error /errorname get put    % Put it in the "failed" dict
  865.       % .applypolicies needs stack: <orig> <merged> <failed>
  866.       exch 4 2 roll exch 4 2 roll .applypolicies exch 4 2 roll exch 4 2 roll
  867.       % Now execute the old Install -- failures after this are not handled
  868.       dup /Install .knownget { { .execinstall } stopped { pop } if } if
  869.       .postinstall stop
  870.     } {
  871.       .postinstall
  872.     } ifelse
  873.   } {
  874.     .postinstall
  875.   } ifelse
  876. } odef
  877.  
  878. % We break out the code after calling the Install procedure into a
  879. % separate procedure, since it is executed even if Install causes an error.
  880. % By making .execinstall a separate operator procedure, we get the stacks
  881. % mostly restored if it fails, except for one element (the operand).
  882. % Thus if it fails, there will be one element left on the op stack.
  883.  
  884. /.execinstall {        % <proc> .execinstall -
  885.   dup    % element left on the stack if the exec fails.
  886.  
  887.     % Because the interpreter optimizes tail calls, we can't just let
  888.     % the body of this procedure be 'exec', because that would lose
  889.     % the stack protection that is the whole reason for having the
  890.     % procedure in the first place. The 'pop' for the dummy element 
  891.     % on the op stack suffices.
  892.   exec
  893.   pop    % See above.
  894. } odef
  895.  
  896. /.postinstall {        % mark ... <failed> <merged> .postinstall -
  897.    matrix currentmatrix .setdefaultmatrix
  898.         % Erase and initialize the page.
  899.    initgraphics
  900.    currentoverprint //false setoverprint 1 setcolor
  901.    .fillpage
  902.    0 setcolor setoverprint
  903.    .beginpage
  904.  
  905.         % Clean up, calling PolicyReport if needed.
  906.         % Stack: mark ... <failed> <merged>
  907. SETPDDEBUG { (Finishing.) = pstack flush } if
  908.  
  909.    exch dup length 0 ne
  910.     { 1 index /Policies get /PolicyReport get
  911.       counttomark 1 add 2 roll cleartomark
  912.       exec
  913.     }
  914.     { cleartomark
  915.     }
  916.    ifelse pop
  917.  
  918. } odef
  919.  
  920. end                % level2dict
  921. .setlanguagelevel
  922.